﻿using System;
using System.IO;
using System.Text;

namespace UMC.Net
{
    public class DataReader
    {
        NetWriteData writeData;
        Action<Exception> _error;
        Action<int> _finish;
        public DataReader(NetWriteData readData, Action<int> finish, Action<Exception> error)
        {
            this.writeData = readData;
            this._error = error;
            this._finish = finish;
        }
        int count = 0;
        bool isOK = true;

        public void Write(byte[] buffer, int offset, int size)
        {
            if (size == 0 && buffer.Length == 0)
            {
                if (offset == -1)
                {
                    isOK = false;
                    if (this._error != null)
                    {
                        this._error(null);
                    }
                }
                else
                {
                    try
                    {

                        _finish(count);

                    }
                    catch (Exception ex)
                    {
                        isOK = false;
                        if (this._error != null)
                            this._error(ex);
                    }
                }
            }
            else
            {
                count += size;
                try
                {
                    if (isOK)
                        this.writeData(buffer, offset, size);
                }
                catch (Exception ex)
                {
                    isOK = false;
                    if (this._error != null)
                        this._error(ex);

                }
            }
        }
    }
    public interface IDataReader
    {
        int Receive(byte[] buffer, int offset, int size);
        // bool IsOver { get; }
    }
    public interface INetBridgeReader
    {
        void Receive(byte[] buffer, int offset, int size);
        bool IsOver { get; }
    }
    public abstract class DataWriter : IDisposable
    {
        
        public abstract void Prepare(ReadOnlySpan<byte> bytes);
        public abstract void Write(ReadOnlySpan<byte> bytes);

        public abstract void Flush();
        public abstract void Dispose();
    }

    public class TextWriter : System.IO.TextWriter
    {
        NetWriteData _hlr;
        byte[] buffers;
        byte[] _buffers;
        int bufferSize = 0;
        char[] _chars = new char[1];
        Encoding _encoding;
        public TextWriter(NetWriteData readData)
        {
            _buffers = System.Buffers.ArrayPool<byte>.Shared.Rent(0x400);
            buffers = _buffers;
            this._hlr = readData;
            _encoding = System.Text.Encoding.UTF8;
        }
        public TextWriter(NetWriteData readData, byte[] buffer)
        {
            buffers = buffer;
            this._hlr = readData;
            _encoding = System.Text.Encoding.UTF8;
        }
        public override Encoding Encoding
        {
            get
            {
                return _encoding;
            }
        }
        protected override void Dispose(bool disposing)
        {
            if (_buffers != null)
            {
                System.Buffers.ArrayPool<byte>.Shared.Return(_buffers);
                _buffers = null;
            }
            buffers = null;
            base.Dispose(disposing);
        }
        public override void Write(char value)
        {
            if (bufferSize + 6 > buffers.Length)
            {
                _hlr(buffers, 0, bufferSize);
                bufferSize = 0;
            }
            _chars[0] = value;
            bufferSize += _encoding.GetBytes(_chars, 0, 1, buffers, bufferSize);

        }
        public void Write(byte[] buffer, int offset, int count)
        {
            if (bufferSize + count > buffers.Length)
            {
                _hlr(buffers, 0, bufferSize);
                _hlr(buffer, offset, count);
                bufferSize = 0;

            }
            else
            {
                Array.Copy(buffer, offset, buffers, bufferSize, count);
                bufferSize += count;
            }

        }
        public void Write(ReadOnlySpan<byte> bytes)
        {
            if (bufferSize + bytes.Length > buffers.Length)
            {

                while (bytes.Length > 0)
                {

                    var t = buffers.Length - bufferSize;
                    if (t > bytes.Length)
                    {

                        bytes.CopyTo(buffers.AsSpan(bufferSize));
                        bufferSize += bytes.Length;
                        break;
                    }
                    else
                    {
                        bytes.Slice(0, t).CopyTo(buffers.AsSpan(bufferSize));
                        _hlr(buffers, 0, buffers.Length);
                        bufferSize = 0;
                        bytes = bytes.Slice(t);

                    }
                }

            }
            else
            {
                bytes.CopyTo(buffers.AsSpan(bufferSize));
                bufferSize += bytes.Length;

            }
        }
        public override void Flush()
        {
            if (bufferSize > 0)
            {
                _hlr(buffers, 0, bufferSize);
                bufferSize = 0;
            }
        }
    }
}
